#include "xRenderScheme.h"
#include "xShader.h"
#include "xTexture.h"
#include "xMaterial.h"
#include "XRenderSystem.h"
#include "xSkeleton.h"


namespace XE
{



	xRenderScheme::xRenderScheme(float dis,xShaderPtr pShader)
		:m_Distance(dis),m_pShader(pShader)
	{
	
			BuildConstantParamterTable();

	}


	xRenderScheme::~xRenderScheme()
	{
		DestoryParameterMap();
	}



	int TechniqueDisComp (const void* first,const void* second)
	{
		return ((xRenderScheme*)first)->m_Distance<((xRenderScheme*)second)->m_Distance;
	}






	bool  xRenderScheme::SetTexture(int index,xTexturePtr pTexture)
	{
		if(index<0||index>MaxTextureLevel -1)
			return false;
		m_Textrue[index] = pTexture;
		return true;

	}

	xTexturePtr xRenderScheme::GetTexture(int index)const 
	{
		if(index<0||index>MaxTextureLevel -1)
			return xTexturePtr();
		return m_Textrue[index];
	}

	int xRenderScheme::GetTexutreNumber() const
	{
		int count = 0;
		for(int i = 0;i<MaxTextureLevel;++i)
		{
			if(m_Textrue[i].isNull())
				break;
			++count;

		}

		return count;
	}

	void xRenderScheme::SetShader(xShaderPtr	 pShader)
	{
		m_pShader = pShader; 
		BuildConstantParamterTable();
	}

	void xRenderScheme::DestoryParameterMap()
	{
		xShaderParameterMapIterator it = m_ParameterMap.begin();
		for(;it!=m_ParameterMap.end();++it)
		{
			delete it->second;
		}

		m_ParameterMap.clear();


		xAutoConstantParameterVector::iterator autoitbegin = m_AutoParameterVector.begin();
        xAutoConstantParameterVector::iterator autoitend = m_AutoParameterVector.end(); 
		for(;autoitbegin!=autoitend;++autoitbegin)
		{
			SafeDelete(*autoitbegin)
		}
		m_AutoParameterVector.clear();

	}







	bool  xRenderScheme::SetConstantValueBySemantic(const xString& SemanticName,float data )
	{
		xShaderParameterMapIterator it = m_ParameterMap.begin();
		xShaderParameterMapIterator itend = m_ParameterMap.end();
		for(;it!=itend;++it)
		{
			if(it->second==NULL)
				continue;
			if(it->second->GetSemantic()==SemanticName)
			{
				return 	it->second->WriteData(&data,sizeof(float));
			}
		}
		return  false;
	}

	bool xRenderScheme::SetConstantValueBySemantic(const xString& SemanticName,int data)
	{
		xShaderParameterMapIterator it = m_ParameterMap.begin();
		xShaderParameterMapIterator itend = m_ParameterMap.end();
		for(;it!=itend;++it)
		{
			if(it->second==NULL)
				continue;
			if(it->second->GetSemantic()==SemanticName)
			{
				return 	it->second->WriteData(&data,sizeof(int));
			}
		}
		return  false;

	}

	bool xRenderScheme::SetConstantValueBySemantic(const xString& SemanticName, const xMatrix* pData)
	{
		xShaderParameterMapIterator it = m_ParameterMap.begin();
		xShaderParameterMapIterator itend = m_ParameterMap.end();
		for(;it!=itend;++it)
		{
			if(it->second==NULL)
				continue;
			if(it->second->GetSemantic()==SemanticName)
			{
				return 	it->second->WriteData(pData,sizeof(xMatrix));
			}
		}
		return  false;

	}

	bool xRenderScheme::SetConstantValueBySemantic(const xString& SemanticName,bool  pData)
	{
		xShaderParameterMapIterator it = m_ParameterMap.begin();
		xShaderParameterMapIterator itend = m_ParameterMap.end();
		for(;it!=itend;++it)
		{
			if(it->second==NULL)
				continue;
			if(it->second->GetSemantic()==SemanticName)
			{
				return 	it->second->WriteData(&pData,sizeof(bool));
			}
		}
		return  false;

	}

	bool xRenderScheme::SetConstantValueBySemantic(const xString& SemanticName,const  xVector3* pData)
	{
		xShaderParameterMapIterator it = m_ParameterMap.begin();
		xShaderParameterMapIterator itend = m_ParameterMap.end();
		for(;it!=itend;++it)
		{
			if(it->second==NULL)
				continue;
			if(it->second->GetSemantic()==SemanticName)
			{
				return 	it->second->WriteData(pData,sizeof(xVector3));
			}
		}
		return  false;

	}
	bool xRenderScheme::SetConstantValueBySemantic(const xString& SemanticName,const  xColor * pData)
	{
		xShaderParameterMapIterator it = m_ParameterMap.begin();
		xShaderParameterMapIterator itend = m_ParameterMap.end();
		for(;it!=itend;++it)
		{
			if(it->second==NULL)
				continue;
			if(it->second->GetSemantic()==SemanticName)
			{
				return 	it->second->WriteData(pData,sizeof(xColor));
			}
		}
		return  false;


	}

	bool xRenderScheme::SetConstantValueBySemantic(const xString& SemanticName, const xVector4* pData)
	{
		xShaderParameterMapIterator it = m_ParameterMap.begin();
		xShaderParameterMapIterator itend = m_ParameterMap.end();
		for(;it!=itend;++it)
		{
			if(it->second==NULL)
				continue;
			if(it->second->GetSemantic()==SemanticName)
			{
				return 	it->second->WriteData(pData,sizeof(xVector4));
			}
		}
		return  false;


	}

	bool xRenderScheme::SetConstantValueBySemantic(const  xString& SemanticName, void* pData,UINT size)
	{
		xShaderParameterMapIterator it = m_ParameterMap.begin();
		xShaderParameterMapIterator itend = m_ParameterMap.end();
		for(;it!=itend;++it)
		{
			if(it->second==NULL)
				continue;
			if(it->second->GetSemantic()==SemanticName)
			{
				return 	it->second->WriteData(pData,size);
			}
		}
		return  false;


	}

	bool xRenderScheme::SetConstantArrayValueBySemantic(const xString&SemanticName,const float* pData,UINT num)
	{
		xShaderParameterMapIterator it = m_ParameterMap.begin();
		xShaderParameterMapIterator itend = m_ParameterMap.end();
		for(;it!=itend;++it)
		{
			if(it->second==NULL)
				continue;
			if(it->second->GetSemantic()==SemanticName)
			{
				return 	it->second->WriteData(pData,sizeof(float)*num);
			}
		}
		return  false;

	}

	bool xRenderScheme::SetConstantArrayValueBySemantic(const xString&SemanticName,const int* pData,UINT num)
	{

		xShaderParameterMapIterator it = m_ParameterMap.begin();
		xShaderParameterMapIterator itend = m_ParameterMap.end();
		for(;it!=itend;++it)
		{
			if(it->second==NULL)
				continue;
			if(it->second->GetSemantic()==SemanticName)
			{
				return 	it->second->WriteData(pData,sizeof(int)*num);
			}
		}
		return  false;
	}


	bool xRenderScheme::SetConstantArrayValueBySemantic(const xString&SemanticName,const bool* pData,UINT num)
	{
		xShaderParameterMapIterator it = m_ParameterMap.begin();
		xShaderParameterMapIterator itend = m_ParameterMap.end();
		for(;it!=itend;++it)
		{
			if(it->second==NULL)
				continue;
			if(it->second->GetSemantic()==SemanticName)
			{
				return 	it->second->WriteData(pData,sizeof(bool)*num);
			}
		}
		return  false;

	}

	bool xRenderScheme::SetConstantArrayValueBySemantic(const xString&SemanticName, const xMatrix* pData,UINT num)
	{
		xShaderParameterMapIterator it = m_ParameterMap.begin();
		xShaderParameterMapIterator itend = m_ParameterMap.end();
		for(;it!=itend;++it)
		{
			if(it->second==NULL)
				continue;
			if(it->second->GetSemantic()==SemanticName)
			{
				return 	it->second->WriteData(pData,sizeof(xMatrix)*num);
			}
		}
		return  false;
	}

	bool xRenderScheme::SetConstantArrayValueBySemantic(const xString& SemanticName,const  xVector3* pData,UINT num)
	{
		xShaderParameterMapIterator it = m_ParameterMap.begin();
		xShaderParameterMapIterator itend = m_ParameterMap.end();
		for(;it!=itend;++it)
		{
			if(it->second==NULL)
				continue;
			if(it->second->GetSemantic()==SemanticName)
			{
				return 	it->second->WriteData(pData,sizeof(xVector3)*num);
			}
		}
		return  false;

	}


	bool xRenderScheme::SetConstantArrayValueBySemantic(const xString& SemanticName,const  xColor * pData,UINT num)
	{
		xShaderParameterMapIterator it = m_ParameterMap.begin();
		xShaderParameterMapIterator itend = m_ParameterMap.end();
		for(;it!=itend;++it)
		{
			if(it->second==NULL)
				continue;
			if(it->second->GetSemantic()==SemanticName)
			{
				return 	it->second->WriteData(pData,sizeof(xColor)*num);
			}
		}
		return  false;
	}

	bool xRenderScheme::SetConstantArrayValueBySemantic(const xString& SemanticName, const xVector4* pData,UINT num)
	{
		xShaderParameterMapIterator it = m_ParameterMap.begin();
		xShaderParameterMapIterator itend = m_ParameterMap.end();
		for(;it!=itend;++it)
		{
			if(it->second==NULL)
				continue;
			if(it->second->GetSemantic()==SemanticName)
			{
				return 	it->second->WriteData(pData,sizeof(xVector4)*num);
			}
		}
		return  false;
	}





	xShaderParameter*  xRenderScheme::GetParameterByName(const xString& name)
	{
		xShaderParameterMapIterator it = m_ParameterMap.find(name);
		if(it==m_ParameterMap.end())
			return NULL;
		return it->second;

	}


	bool xRenderScheme::SetConstantValue(const xString& name,float pData)
	{
		xShaderParameter* pParameter = GetParameterByName(name);
		if(pParameter==NULL)
			return false;
		return 	pParameter->WriteData(&pData,sizeof(float) );

	}


	bool xRenderScheme:: SetConstantValue(const xString& name,DWORD data)
	{
		xShaderParameter* pParameter = GetParameterByName(name);
		if(pParameter==NULL)
			return false;
		return 	pParameter->WriteData(&data,sizeof(DWORD) );
	}


	bool xRenderScheme::SetConstantValue(const  xString& name, void* pData,UINT size)
	{

		xShaderParameter* pParameter = GetParameterByName(name);
		if(pParameter==NULL)
			return false;
		return 	pParameter->WriteData(pData,size );

	}


	bool xRenderScheme::SetConstantValue(const xString& name,int pData)
	{
		xShaderParameter* pParameter = GetParameterByName(name);
		if(pParameter==NULL)
			return false;

		return 	pParameter->WriteData(&pData,sizeof(int) );
	}


	bool xRenderScheme::SetConstantValue(const xString& name,const  xMatrix* pData)
	{
		xShaderParameter* pParameter = GetParameterByName(name);
		if(pParameter==NULL)
			return false;

		return 	pParameter->WriteData(pData,sizeof(xMatrix) );
	}


	bool xRenderScheme::SetConstantValue(const xString& name,bool  pData)
	{
		xShaderParameter* pParameter = GetParameterByName(name);
		if(pParameter==NULL)
			return false;

		return 	pParameter->WriteData(&pData,sizeof(bool) );
	}

	bool xRenderScheme::SetConstantValue(const xString& name,const  xVector3* pData)
	{
		xShaderParameter* pParameter = GetParameterByName(name);
		if(pParameter==NULL)
			return false;

		return 	pParameter->WriteData(pData,sizeof(xVector3) );
	}


	bool  xRenderScheme::SetConstantValue(const xString&name, const xVector2* pData)
	{
		xShaderParameter* pParameter = GetParameterByName(name);
		if(pParameter==NULL)
			return false;
		return 	pParameter->WriteData(pData,sizeof(xVector2) );

	}

	bool xRenderScheme::SetConstantValue(const xString& name,const  xColor * pData)
	{
		xShaderParameter* pParameter = GetParameterByName(name);
		if(pParameter==NULL)
			return false;

		return 	pParameter->WriteData(pData,sizeof(xColor) );
	}



	bool  xRenderScheme::SetConstantValue(const xString& name, const xVector4* pData)
	{
		xShaderParameter* pParameter = GetParameterByName(name);
		if(pParameter==NULL)
			return false;

		return 	pParameter->WriteData(pData,sizeof(xVector4) );
	}


	bool xRenderScheme::SetConstantArrayValue(const xString&name,const  float* pData,UINT num)
	{
		xShaderParameter* pParameter = GetParameterByName(name);
		if(pParameter==NULL)
			return false;

		return 	pParameter->WriteData(pData,sizeof(float)*num );

	}

	bool xRenderScheme::SetConstantArrayValue(const xString&name,const  int* pData,UINT num)
	{
		xShaderParameter* pParameter = GetParameterByName(name);
		if(pParameter==NULL)
			return false;

		return 	pParameter->WriteData(pData,sizeof(int)*num );
	}

	bool xRenderScheme::SetConstantArrayValue(const xString&name, const bool* pData,UINT num)
	{
		xShaderParameter* pParameter = GetParameterByName(name);
		if(pParameter==NULL)
			return false;

		return 	pParameter->WriteData(pData,sizeof(bool)*num );
	}


	bool xRenderScheme::SetConstantArrayValue(const xString&name,const xMatrix* pData,UINT num)
	{
		xShaderParameter* pParameter = GetParameterByName(name);
		if(pParameter==NULL)
			return false;

		return 	pParameter->WriteData(pData,sizeof(xMatrix)*num );
	}



	bool xRenderScheme::SetConstantArrayValue(const xString& name,const  xVector3* pData,UINT num)
	{

		xShaderParameter* pParameter = GetParameterByName(name);
		if(pParameter==NULL)
			return false;

		return 	pParameter->WriteData(pData,sizeof(xVector3)*num );

	}
	bool xRenderScheme::SetConstantArrayValue(const xString& name,const  xColor * pData,UINT num)
	{
		xShaderParameter* pParameter = GetParameterByName(name);
		if(pParameter==NULL)
			return false;

		return 	pParameter->WriteData(pData,sizeof(xColor)*num );

	}

	bool xRenderScheme::SetConstantArrayValue(const xString& name, const xVector4* pData,UINT num)
	{
		xShaderParameter* pParameter = GetParameterByName(name);
		if(pParameter==NULL)
			return false;

		return 	pParameter->WriteData(pData,sizeof(xVector4)*num );
	}


	xShaderParameter* xRenderScheme::CreateParameter\
		(const xString& name,const xString& SemanticName ,XSHADERPARAMETER_TYPE ParaType,UINT size,const ParaMap& annoMap)
	{
		//-------if is autoConstanPara
		if(AutoConstantParameter::IsAutoConstantPara(SemanticName))
		{
			if(HasAutoContantParameter(SemanticName))
			{
				xLogMessager::getSingleton().logMessage("Create AutoContantparameter fail has same SemnaticName");
				return NULL;

			}else
			{
				AutoConstantParameter * pAutoPara = \
					new AutoConstantParameter(name,AutoConstantParameter::GetAutoType(SemanticName));
				m_AutoParameterVector.push_back(pAutoPara);
				pAutoPara->SetSize(size);
				return pAutoPara;

			}
		}else
		{

			xShaderParameter* pPara =   GetParameterByName(name);
			if(pPara!=NULL)
			{
				xLogMessager::getSingleton().logMessage("Create ShaderParameter Fail,has same name parameter");
				return NULL;
			}
			pPara = new xShaderParameter(name);
			pPara->SetSize(size);
			pPara->SetType(ParaType);
			pPara->SetAnnotationMap(annoMap)
;			if(SemanticName.empty()==false)
			{
				pPara->SetSemantic(SemanticName);
			}
			m_ParameterMap.insert(std::make_pair(name.c_str(),pPara));
			return pPara;
		}
		return NULL;
	}



	xShaderParameter*  xRenderScheme::CreateParameter(const xString& name,XSHADERPARAMETER_TYPE ParaType,UINT size)
	{

		xShaderParameter* pPara =   GetParameterByName(name);
		if(pPara!=NULL)
		{
			xLogMessager::getSingleton().logMessage("Create ShaderParameter Fail,has same name parameter");
			return NULL;
		}
		pPara = new xShaderParameter(name);
		pPara->SetSize(size);
		pPara->SetType(ParaType);
		m_ParameterMap.insert(std::make_pair(name.c_str(),pPara));
		return pPara;

	}





	bool xRenderScheme::HasAutoContantParameter(const xString& SemanticName)
	{


		xAutoConstantParameterVector::iterator it =  m_AutoParameterVector.begin();
		for(;it!=m_AutoParameterVector.end();++it)
		{
			if((*it)->GetSemantic()==SemanticName)
				return true;
		}
		return false;

	}


	HRESULT xRenderScheme::BuildConstantParamterTable()
	{
		DestoryParameterMap();
		if(m_pShader.isNull())
			return X_FAIL;
		UINT paraCount = m_pShader->GetParameterCount();
		if(paraCount==0)
			return X_FAIL;
		for(UINT i = 0;i<paraCount;++i)
		{
		   xShaderParameter tempara("temanem");
		   if(FAILED(m_pShader->GetParameterInfor(i,tempara)))
			   continue;
          xShaderParameter* pNewPara = CreateParameter(tempara.GetName(),tempara.GetSemantic(),\
			  tempara.GetType(),tempara.GetSize(),tempara.GetAnnotationMap());
		  if(pNewPara!=NULL&&(tempara.GetSize()!=0&&tempara.GetData()!=NULL))
		  {
			  pNewPara->WriteData(tempara.GetData(),tempara.GetSize());
		  }

		  

		}
		return X_OK;

	}


	//HRESULT xRenderScheme::AddParameter(const xShaderParameter& para)
	//{
	//	if( GetParameterByName(para.GetName())!=NULL)
	//		return X_FAIL;

	//	xShaderParameter* ptem =new xShaderParameter(para);
	//	m_ParameterMap.insert(std::make_pair(para.GetName(),ptem));

	//	return X_OK;
	//}


	bool xRenderScheme::UpdateParameter(XRenderSystem* pRender)
	{
		
		if(pRender==NULL)
			return false;
		if(m_pShader.isNull())
			return false;	
		xShaderParameterMapIterator it = m_ParameterMap.begin();
		for(;it!=m_ParameterMap.end();++it)
		{
			xShaderParameter* pShaderPara = it->second;
			
			if(pShaderPara==NULL)
				continue;

			if(pShaderPara->GetData()==NULL)
			{	
				if(pShaderPara->NeedupdateAnnotation())
					pShaderPara->upDateAnnotation();

				continue;
			}
		

			HRESULT hr =X_OK;
			//if(it->second->GetSize()==64)
			//{
			//	hr = m_pEffect->SetMatrix(it->second->GetName().c_str(),(xMatrix*)(it->second->GetData()));
			//	//hr = m_pEffect->SetMatrixTranspose(it->second->GetName().c_str(),(xMatrix*)(it->second->GetData()));

			//}else
			//{
			//	void* ptem =(void*) it->second->GetData();
			//	if(it->second->GetType()==XSPT_TEXTURE)
			//	{
			//		int cc = *((int*)(it->second->GetData()));
			//	    LPDIRECT3DTEXTURE9 pText = (LPDIRECT3DTEXTURE9)cc;
			//	    m_pEffect->SetTexture(it->second->GetName().c_str(),pText);
			//	}else
			{
				hr =  	m_pShader->SetConstantValue(pShaderPara->GetName().c_str(),pShaderPara->GetData(),pShaderPara->GetSize());
			}


			//	}

			if(FAILED(hr))
			{
				xLogMessager::getSingleton().logMessage(\
					"Effect Set Parameter err,effect is"+ m_pShader->GetName()+",parameter is"+it->second->GetName());
			}
		}

	

		xAutoConstantParameterVector::iterator autoit  =m_AutoParameterVector.begin();
		xAutoConstantParameterVector::iterator autoitend  =m_AutoParameterVector.end();
		for(;autoit!=autoitend;++autoit)
		{
			AutoConstantParameter* para = *autoit;
			if(para==NULL)
				continue;
			switch ( para->GetAutoType())
			{
			case ACT_WORLD_MATRIX:
				{
					m_pShader->SetConstantValue(para->GetName().c_str(),pRender->GetWorldMatrix(),para->GetSize());
					break;
				}
			case	ACT_VIEW_MATRIX:
				{
					m_pShader->SetConstantValue(para->GetName().c_str(),pRender->GetViewMatrix(),para->GetSize());
					break;
				}

			case	ACT_PROJECTION_MATRIX:
				{
					m_pShader->SetConstantValue(para->GetName().c_str(),pRender->GetProjectMatrix(),para->GetSize());
					break;
				}

			case	ACT_VIEWPROJ_MATRIX:
				{
					xMatrix ViewProject = (*pRender->GetViewMatrix())*(*pRender->GetProjectMatrix());
					m_pShader->SetConstantValue(para->GetName().c_str(),&ViewProject,para->GetSize());
					break;
				}

			case	ACT_WORLDVIEW_MATRIX:
				{
					xMatrix WorldViewmat = (*pRender->GetWorldMatrix())*(*pRender->GetViewMatrix());
					m_pShader->SetConstantValue(para->GetName().c_str(),&WorldViewmat,para->GetSize());
					break;
				}

			case	ACT_WORLDVIEWPROJ_MATRIX:
				{
					xMatrix WorldViewProjectmat = (*pRender->GetWorldMatrix())*(*pRender->GetViewMatrix());
					WorldViewProjectmat*=*pRender->GetProjectMatrix();
					m_pShader->SetConstantValue(para->GetName().c_str(),&WorldViewProjectmat,para->GetSize());
					break;
				}
			case ACT_INVSER_VIEW_MATRIX:
				{

				xMatrix InverViewmat ;
				xMath::MatrixInverse(InverViewmat,*(pRender->GetViewMatrix()));

				m_pShader->SetConstantValue(para->GetName().c_str(),&InverViewmat,para->GetSize());
				break;
				}

			case ACT_WORLD_MATRIX_ARRAY:
				{
					WORD BoneNumber = 0;
					const  xMatrix* pMatrixArray=xSkeleton::GetBoneTransMatrix();
					//const  xMatrix* pMatrixArray=pRender->GetBoneMatrixArray(BoneNumber);
                   	m_pShader->SetConstantValue(para->GetName().c_str(),pMatrixArray,para->GetSize());
					break;
				}

			case    ACT_TEXTURE_0:
			case	ACT_TEXTURE_1:
			case	ACT_TEXTURE_2:
			case	ACT_TEXTURE_3:
			case	ACT_TEXTURE_4:
		    case	ACT_TEXTURE_5:
			case	ACT_TEXTURE_6:
			case	ACT_TEXTURE_7:
				{
				    const  xTexture* pTexture =   pRender->GetTexture(para->GetAutoType()-ACT_TEXTURE_0);
				     m_pShader->SetTextureValue(para->GetName(),pTexture);
					break;
				}
	
			}
		}


		
		return true;
	}



}